package com.morder.provider;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Locale;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;

import com.morder.net.HttpExecutor;
import com.morder.net.HttpExecutor.Listener;
import com.morder.util.Base64;
import com.morder.util.Constant;
import com.morder.util.NetworkFailException;

public abstract class BaseRequest {

  public Context mContext;

  public static final int NORMAL_STATUS = 0;
  public static final int FAIL_STATUS = 1;
  public static final int OTHER_ERR_STATUS = 3;
  public static final int NETWORK_EXCEPTION = 100;
  public static final int IO_EXCEPTION = 200;

  private int mResultCode = 0;
  private String mMsg = "";

  public BaseRequest(Context context) {
    this.mContext = context;
  }

  private RequestListener mListener = null;

  public boolean post(String requestName, String url, RequestListener listener) {
    registerRequestListener(listener);
    boolean result = false;
    try {
      tryPost(requestName, url);
      result = true;
    } catch (NetworkFailException e) {
      e.printStackTrace();
      setResult(NETWORK_EXCEPTION);
    } catch (IOException e) {
      e.printStackTrace();
      setResult(NETWORK_EXCEPTION);
    } finally {
      unRegisterRequestListener();
    }
    return result;
  }

  private void tryPost(String requestName, String url) throws NetworkFailException, IOException {
    String request = createRequest(requestName);
    // post and get reponse
    request = new String(Base64.encode(request));
    if ((request == null) || (request.length() <= 0)) {
      throw new IllegalStateException("createRequest fail");
    }
    postAndGetResponse(url, request);
  }

  private String createRequest(String requestName) {
    String request = null;
    try {
      request = tryCreateRequest(requestName);
    } catch (JSONException e) {
      e.printStackTrace();
    }
    return request;
  }

  private void parseResponse(String input) {
    try {
      tryParseResponse(input);
    } catch (IOException e) {
      setResult(IO_EXCEPTION);
    } catch (JSONException e) {
      e.printStackTrace();
      setResult(NETWORK_EXCEPTION);
    }
  }

  private String tryCreateRequest(String requestName) throws JSONException {
    JSONObject object = new JSONObject();
    String api = "api";
    object.put(Constant.API, api);
    Contexts contexts = new Contexts();
    String lang = getLange();
    System.out.println("lang = " + lang);
    contexts.setLang(lang);
    String prefver = "perfver";
    contexts.setPrefver(prefver);
    object.put(Constant.CONTEXT, getParamsValue(contexts));
    object.put(Constant.METHOD, requestName);
    onParseRequest(object);
    return object.toString();
  }

  private String getLange() {
    String area = mContext.getResources().getConfiguration().locale.getCountry();
    String language = Locale.getDefault().getLanguage();
    return (language + "-" + area).toLowerCase();
  }

  private JSONObject getParamsValue(Contexts contexts) {
    JSONObject object = new JSONObject();
    return object;
  }

  private void tryParseResponse(String input) throws IOException, JSONException {
    JSONObject result = new JSONObject(input);
    String api = result.optString(Constant.Data.API);
    System.out.println("api: " + api);
    JSONObject error = result.optJSONObject(Constant.ERROR);
    if ((error != null) && (error.length() > 0) && !"".equals(error)) {
      int code = error.optInt(Constant.Data.CODE);
      setResult(code);
      String msg = error.optString(Constant.Data.MSG);
      if (msg != null) {
        setMsg(msg);
      }
      return;
    }
    JSONObject context = result.optJSONObject(Constant.CONTEXT);
    if ((context != null) && (context.length() > 0) && !"".equals(context)) {
      JSONObject perfver = context.optJSONObject(Constant.Contexts.PREFVER);
      String perfverVer = perfver.optString(Constant.Contexts.VER);
      System.out.println("perfverVer: " + perfverVer);
      String perfverMsg = perfver.optString(Constant.Contexts.MSG);
      System.out.println("perfverMsg: " + perfverMsg);
      JSONObject appLatestVer = context.optJSONObject(Constant.Contexts.APPLATESTVER);
      String appverMsg = appLatestVer.optString(Constant.Contexts.MSG);
      System.out.println("appverMsg: " + appverMsg);
      String ver = appLatestVer.optString(Constant.Contexts.VER);
      System.out.println("ver: " + ver);
      String appverUrl = appLatestVer.optString(Constant.Contexts.URL);
      System.out.println("appverUrl: " + appverUrl);
    }
    String method = result.optString(Constant.METHOD);
    System.out.println("method: " + method);
    onParseResponse(result);
  }

  private void setMsg(String reason) {
    mMsg = reason;
  }

  public String getMsg() {
    return mMsg;
  }

  private void setResult(int code) {
    mResultCode = code;
  }

  public int getResuleCode() {
    return mResultCode;
  }

  protected abstract void onParseRequest(JSONObject object);

  protected abstract void onParseResponse(JSONObject result);

  private void registerRequestListener(RequestListener listener) {
    unRegisterRequestListener();
    mListener = listener;
  }

  private void unRegisterRequestListener() {
    mListener = null;
  }

  protected void notifyListener(String info) {
    if (mListener != null) {
      mListener.onRequestProcessInfo(info);
    }
  }

  public static interface RequestListener {
    public void onRequestProcessInfo(String info);
  }

  private void postAndGetResponse(String url, String input) throws NetworkFailException {
    new HttpExecutor.Post(mContext).setTryTimes(2).setUri(url).addRequest("request", input)
        .setResponseListener(new Listener() {

          @Override
          public void OnResponse(boolean success, byte[] content) {
            String response;
            if (success) {
              try {
                response = Base64.decode(new String(content));
                parseResponse(response);
              } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
              }
            } else {
              if ((content == null) || (content.length == 0)) {
                System.out.println("fail");
                setResult(NETWORK_EXCEPTION);
              } else {
                System.out.println("fail:" + content);
                try {
                  response = Base64.decode(new String(content));
                  parseResponse(response);
                } catch (UnsupportedEncodingException e) {
                  e.printStackTrace();
                }
              }
            }
          }
        }).execute();
  }
}